#include "tcp_server.h"
#include "config.h"
#include "log.h"
#include "fd_manager.h"

namespace johnsonli
{

    //客户端2分钟没有发送请求，就断开此连接
    static johnsonli::ConfigVar<uint64_t>::ptr g_tcp_server_read_timeout =
    johnsonli::Config::Lookup("tcp_server.read_timeout", (uint64_t)(60 * 1000 * 2),
            "tcp server read timeout");

    static johnsonli::Logger::ptr g_logger = LOG_NAME("system");

    TcpServer::TcpServer() {}

    TcpServer::TcpServer(const std::string& servername,
                    johnsonli::IOManager* worker,
                    johnsonli::IOManager* io_worker,
                    johnsonli::IOManager* accept_worker)
        :m_worker(worker)
        ,m_ioWorker(io_worker)
        ,m_acceptWorker(accept_worker)
        ,m_recvTimeout(g_tcp_server_read_timeout->getValue())
        ,m_isStop(true) {
        if(servername.empty())
        {
            m_name = "johnsonli/1.0.0";
        }
        else
        {
            m_name = servername;
        }
    }

    TcpServer::~TcpServer() 
    {
        for(auto& i : m_socks) 
        {
            i->close();
        }
        m_socks.clear();
    }

    bool TcpServer::bind(johnsonli::Address::ptr addr, bool ssl) 
    {
        std::vector<Address::ptr> addrs;
        std::vector<Address::ptr> fails;
        addrs.push_back(addr);
        return bind(addrs, fails, ssl);
    }

    bool TcpServer::bind(const std::vector<Address::ptr>& addrs
                        ,std::vector<Address::ptr>& fails
                        ,bool ssl) 
    {
        m_ssl = ssl;

        //每一个地址都会创建一个 listen socket
        for(auto& addr : addrs)
        {
            Socket::ptr sock = Socket::CreateTCP(addr);
            if(!sock->bind(addr))
            {
                LOG_ERROR(g_logger) << "bind fail errno="
                    << errno << " errstr=" << strerror(errno)
                    << " addr=[" << addr->toString() << "]";
                fails.push_back(addr);
                continue;
            }

            if(!sock->listen()) {
                LOG_ERROR(g_logger) << "listen fail errno="
                    << errno << " errstr=" << strerror(errno)
                    << " addr=[" << addr->toString() << "]";
                fails.push_back(addr);
                continue;
            }

            m_socks.push_back(sock);
        }

        //有创建失败的
        if(!fails.empty()) {
            m_socks.clear();
            return false;
        }

        for(auto& i : m_socks) {
            LOG_INFO(g_logger) << "type=" << m_type
                << " name=" << m_name
                << " ssl=" << m_ssl
                << " server bind success: " << *i;
        }
        return true;
    }

    void TcpServer::startAccept(Socket::ptr sock) 
    {
        while(!m_isStop)
        {
            LOG_DEBUG(g_logger) << "startAccept";
            Socket::ptr client = sock->accept();
            //accept成功
            if(client)
            {
                // 客户端超时没发数据过来，就会断开连接
                client->setRecvTimeout(m_recvTimeout);
                //专门处理client socket的协程调度器
                //LOG_INFO(g_logger) << "schedule handleClient";
                // m_ioWorker可以是多线程，因为会有多个client连接，每个线程都可以处理
                m_ioWorker->schedule(std::bind(&TcpServer::handleClient, shared_from_this(), client));
            }
            else
            {
                LOG_ERROR(g_logger) << "accept errno=" << errno
                    << " errstr=" << strerror(errno);
            }
        }
    }

    bool TcpServer::start() 
    {
        if(!m_isStop)
        {
            return true;
        }
        m_isStop = false;

        //每个listen socket都需要进行accept，所以可以有多个线程，每个线程负责一个accept
        for(auto& sock : m_socks)
        {
            //专门负责accept的协程调度器
            m_acceptWorker->schedule(std::bind(&TcpServer::startAccept,
                    shared_from_this(), sock));
        }
        return true;
    }

    void TcpServer::stop() 
    {
        m_isStop = true;
        auto self = shared_from_this();
        m_acceptWorker->schedule([this, self](){
            for(auto& sock : m_socks)
            {
                sock->cancelAll();
                sock->close();
            }
            m_socks.clear();
        });
    }
    
    void TcpServer::handleClient(Socket::ptr client) 
    {
        LOG_INFO(g_logger) << "handleClient: " << *client;
    }
}